package com.booter.producer.config.sentinel;

import com.alibaba.csp.sentinel.datasource.Converter;
import com.alibaba.csp.sentinel.datasource.ReadableDataSource;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.listener.RedisMessageListenerContainer;

import java.util.List;

/**
 * private boolean clusterMode; // 标识是否为集群限流配置
 * private ClusterFlowConfig clusterConfig; // 集群限流相关配置项
 * // （必需）全局唯一的规则 ID，由集群限流管控端分配.
 * private Long flowId;
 * // 阈值模式，默认（0）为单机均摊，1 为全局阈值.
 * private int thresholdType = ClusterRuleConstant.FLOW_THRESHOLD_AVG_LOCAL;
 * private int strategy = ClusterRuleConstant.FLOW_CLUSTER_STRATEGY_NORMAL;
 * // 在 client 连接失败或通信失败时，是否退化到本地的限流模式
 * private boolean fallbackToLocalWhenFail = true;
 */

/***
 * sentinel-cluster-client-default: 默认集群流控 client 模块，使用 Netty 进行通信，提供接口方便序列化协议扩展
 * sentinel-cluster-server-default: 默认集群流控 server 模块，使用 Netty 进行通信，提供接口方便序列化协议扩展；同时提供扩展接口对接规则判断的具体实现（TokenService），
 * 默认实现是复用 sentinel-core 的相关逻辑
 *
 */

public class SentinelDataSource implements InitializingBean {

    private RedisMessageListenerContainer container;

    private ObjectMapper objectMapper = new ObjectMapper();

    @Autowired
    private RedisTemplate<String, String> redisTemplate;

    public SentinelDataSource(RedisMessageListenerContainer container) {
        this.container = container;
        this.objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
    }

    @Override
    public void afterPropertiesSet() {
        // 将规则保存到redis对应的key中 ，格式为json,使用redis发布订阅实现规则变更
        //set sentinel '[{"resource":"user/index","count":"2","grade":"1"}]'
        //publish Test '[{"resource":"user/index","count":"2","grade":"1"}]'
        Converter<String, List<FlowRule>> parser = source -> {
            try {
                return this.objectMapper.readValue(source, new TypeReference<List<FlowRule>>() {
                });
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return null;
        };


//        source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {});
//        RedisConnectionConfig config = RedisConnectionConfig.builder().withHost("127.0.0.1").withPort(6379).build();
        //ruleKey 保存规则对应的key ,channel 规则发布订阅时对应的key
//       ReadableDataSource<String, List<FlowRule>> redisDataSource = new RedisDataSource<> (config, "sentinel", "push-crawler-channel", parser);
        ReadableDataSource<String, List<FlowRule>> red = new CustomerRedisDataSource(this.redisTemplate, "sentinel", "push-crawler-channel", parser, this.container);
        FlowRuleManager.register2Property(red.getProperty());

    }
}
